<?php
/**
 * shimansky.biz
 *
 * Static web site core scripts
 * @package shimansky.biz
 * @author Serguei Shimansky <serguei@shimansky.biz>
 * @copyright Serguei Shimansky 10:07 24.06.2012
 * @access public
 * @version 0.2
 * @link https://bitbucket.org/englishextra/shimansky.biz
 * @link https://github.com/englishextra/shimansky.biz.git
 * @link https://gist.github.com/2981888
 * @link http://pastebin.com/y2Gs4bzE
 */
 
/**
 * methods:
 * 1. is_utf8
 * 2. safe_str 
 * 3. get_post
 * 4. fix_str_for_js 
 * 5. js_unescape
 * 6. ensure_amp 
 * 7. ensure_lt_gt 
 * 8. cut_last_160_160 
 * 9. cut_last_160_183 
 * 10. cut_last_br 
 * 11. ord_space 
 * 12. ord_underscore 
 * 13. ord_hypher 
 * 14. remove_tags 
 * 15. remove_ents 
 * 16. remove_comments 
 * 17. has_http
 * 18. is_ip
 * 19. write_file
 * 20. clear_data
 * 21. remove_dir_content
 * 22. remove_bbcoded
 * 23. clean_title 
 * 24. clean_xhtml
 * 25. html_to_safe_str
 * 26. random_anchor
 */
class Swamper {

	/**
	 * 	There is a difference between the two: If you write an empty __construct() function, you overwrite any inherited __construct() from a parent class.
	 * 	So if you don't need it and you do not want to overwrite the parent constructor explicitly, don't write it at all.
	 */
    function __construct() {
	
    }
    
	public function is_utf8($s) {
	    // From http://w3.org/International/questions/qa-forms-utf-8.html
	    return preg_match('%^(?:
	    [\x09\x0A\x0D\x20-\x7E] # ASCII
	    | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
	    | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
	    | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
	    | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
	    | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
	    | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
	    | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
	    )*$%xs', $s);
	}

	public function safe_str($s) {
		return str_replace(array("\n", "\r", "\t", "\v", "\0", "\x0B"), '', preg_replace("/[^\x20-\xFF]/", "", trim(@strval($s))));
	}

	public function get_post($s, $v = '') {
		if (isset ($_GET[$s]) || isset ($_POST[$s])) {
			$v = isset ($_GET[$s]) ? $_GET[$s] : $_POST[$s];
			if (is_array($v)) {
				foreach ($v as &$v1) {
					$v1 = urldecode($v1);
					$v1 = strtr($v1, array_flip(get_html_translation_table(HTML_ENTITIES)));
					$v1 = trim($v1);
					$v1 = $this->safe_str($v1);
				}
				unset($v1);
			} else {
				$v = urldecode($v);
				$v = strtr($v, array_flip(get_html_translation_table(HTML_ENTITIES)));
				$v = trim($v);
				$v = $this->safe_str($v);
			}
		}
		return $v;
	}

	public function fix_str_for_js($s) {
		$s = str_replace("'", '\&#39;', $s);
		return $s;
	}

	public function js_unescape($s) {
		return preg_replace('/\\\u([0-9a-f]{4})/ie', "chr(hexdec('\\1'))", $s);
	}

	public function ensure_amp($s) {
		$s = str_replace('&', '&amp;', $s);
		$s = str_replace(array('&amp;amp;', '&amp;#'), array('&amp;', '&#'), $s);
		$s = preg_replace("/(\&amp\;)([a-z0-9]+)(\;)/ei", "'&'.('\\2').';'", $s);
		$s = preg_replace("/(\&\#)([a-z0-9]+)(\;)/ei", "'&#'.('\\2').';'", $s);
		return $s;
	}

	public function ensure_lt_gt($s) {
		$s = str_replace('<', '&lt;', $s);
		$s = str_replace('>', '&gt;', $s);
		$s = str_replace(array('&amp;lt;', '&amp;gt;'), array('&lt;', '&gt;'), $s);
		return $s;
	}

	public function cut_last_160_160($s) {
		$s = preg_replace("/\&\#160\;\&\#160\; \r\n$/", '', $s);
		$s = preg_replace("/\&\#160\;\&\#160\; \n$/", '', $s);
		return $s;
	}

	public function cut_last_160_183($s) {
		$s = preg_replace("/\&\#160\;\&\#183\; \r\n$/", '', $s);
		$s = preg_replace("/\&\#160\;\&\#183\; \n$/", '', $s);
		return $s;
	}

	public function cut_last_br($s) {
		$s = preg_replace("/\<br \/\>\r\n$/i", '', $s);
		$s = preg_replace("/\<br \/\>\n$/i", '', $s);
		return $s;
	}

	public function ord_space($s) {
		return trim(preg_replace("/[\ ]+/", " ", $s));
	}

	public function ord_underscore($s) {
		return trim(preg_replace("/[\_]+/", "_", $s));
	}

	public function ord_hypher($s) {
		return trim(preg_replace("/[\-]+/", "-", $s));
	}

	public function remove_tags($s) {
		$s = stripslashes($s);
		$s = preg_replace("'<script[^>]*?>.*?</script>'si", ' ', $s);
		$s = preg_replace("'<style[^>]*?>.*?</style>'si", ' ', $s);
		$s = preg_replace("'<[\/\!]*?[^<>]*?>'si", ' ', $s);
		$s = $this->ord_space($s);
		return $s;
	}

	public function remove_ents($s) {
		$s = preg_replace("/(\&)([A-Za-z0-9\#]+)(\;)/ei", "' '", $s);
		return $s;
	}

	public function remove_comments($s) {
		$s = preg_replace("/(\<!--)(.*?)(-->)/ie", "", $s);
		return $s;
	}

	public function has_http($s, $r = false) {
		if (preg_match("/^(http|https|ftp)\:\/\//", $s) &&
			!preg_match("/^\//", $s)) {
			return $r = true;
		}
	}

	public function is_ip($ip) {
		//first of all the format of the ip address is matched
		if(preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$ip)) {
			//now all the intger values are separated
			$parts=explode(".",$ip);
			//now we need to check each part can range from 0-255
			foreach($parts as $ip_parts)  {
				if(intval($ip_parts)>255 || intval($ip_parts)<0) {
					return false; //if number is not within range of 0-255
				}
			}
			return true;
		} else {
			return false; //if format of ip address doesn't matches
		}
	}

	public function write_file($data, $w, $type) {
		if (!$fo = fopen($data, $type)) {
			die('Cannot open file: ' . $data);
		}
		if (!is_writable($data)) {
			die('Cannot write file: ' . $data);
		}
		flock($fo, LOCK_EX);
		fputs($fo, $w);
		fflush($fo);
		flock($fo, LOCK_UN);
		fclose($fo);	
	}

	public function clear_data($data) {
		$w = '';
		if (!file_exists($data) || !$fo = fopen($data, "w+")) {
			die('Cannot open file: ' . $data);
		}
		flock($fo, LOCK_EX);
		fputs($fo, $w);
		fflush($fo);
		flock($fo, LOCK_UN);
		fclose($fo);
	}
	
	public function remove_dir_content($dirname = '.') {
	    if (is_dir($dirname)) {
	        echo '<strong>' . $dirname . '</strong> is a directory.<br />';
	        if ($handle = @opendir($dirname)) {
	            while (($file = readdir($handle)) !== false) {
	                if ($file != "." && $file != "..") {
	                    echo '<strong>' . $file . '</strong> deleted<br />';
	
	                    $fullpath = $dirname . '/' . $file;
	
	                    if (is_dir($fullpath)) {
	                        $this->remove_dir_content($fullpath);
	                        @rmdir($fullpath);
	                    } else {
	                        @unlink($fullpath);
	                    }
	                }
	            }
	            closedir($handle);
	        }
	    }
	}

	public function remove_bbcoded($s) {

		$a = array(
			'(\[img\])(.*?)(\[\/img\])' => '',
			'(\[img\=left\])(.*?)(\[\/img\])' => '',
			'(\[img\=right\])(.*?)(\[\/img\])' => '',
			'(\[color\=[a-zA-Z0-9\#]+\])(.*?)(\[\/color\])' => '',
			'(\[)(.*?)(\])' => ''
		);

		foreach($a as $k => $v) {
			$s = preg_replace("/${k}/", $v, $s);
		}

		return $s;
	}

	public function clean_title($s) {
		$s = str_replace('&#160;', ' ', $s);
		$s = str_replace('&nbsp;', ' ', $s);
		$s = str_replace('\'', '&#39;', $s);
		$s = str_replace('№', '&#x2116;', $s);
		$s = str_replace('“', '&#171;;', $s);
		$s = str_replace('”', '&#187;', $s);
		$s = str_replace('—', '&#8212;', $s);
		$s = $this->remove_tags($s);
		$s = $this->ensure_lt_gt($s);
		$s = str_replace(array("\n", "\r", "\t", "\v", "\0", "\x0B"), '', preg_replace("/[^\x20-\xFF]/", " ", trim(@strval($s))));
		$s = $this->ord_space($s);
		$s = $this->ensure_amp($s);
		return $s;
	}

	public function clean_xhtml($s) {
		$s = strval($s);

		$a = array(
	'¦' => '&#166;',
	'§' => '&#167;',
	'©' => '&#169;',
	'«' => '&#171;',
	'®' => '&#174;',
	'°' => '&#176;',
	'±' => '&#177;',
	'·' => '&#183;',
	'»' => '&#187;',
	'Ё' => 'Е',
	'е' => 'е',
	'—' => '&#8212;',
	'‘' => '&#8216;',
	'’' => '&#8217;',
	'“' => '&#147;',
	'“' => '&#171;;',
	'”' => '&#148;',
	'”' => '&#187;',
	'„' => '&#132;',
	'•' => '&#149;',
	'‰' => '%',
	'№' => '&#8470;',
	'™' => '&#153;',
	'\'' => '&#39;',
	'`' => '&#39;',
	' & ' => ' &amp; ',
	'&bull;' => '&#8226;',
	'&cent;' => '&#162;',
	'&copy;' => '&#169;',
	'&darr;' => '&#8595;',
	'&eacute;' => '&#233;',
	'&euro;' => '&#8364;',
	'&iexcl;' => '&#161;',
	'&laquo;' => '&#171;',
	'&ldquo;' => '&#8220;',
	'&mdash;' => '&#8212;',
	'&middot;' => '&#183;',
	'&nbsp;' => '&#160;',
	'&pound;' => '&#163;',
	'&raquo;' => '&#187;',
	'&rdquo;' => '&#8221;',
	'&reg;' => '&#174;',
	'&trade;' => '&#8482;',
	'&yen;' => '&#165;',
	'(c)' => '&#169;',
	'NN' => '&#x2116;'
		);
		foreach ($a as $k => $v) {
			$s = str_replace($k, $v, $s);
		}
		$s = preg_replace("/[\ ]+/s", ' ', $s);
		$s = preg_replace("/[\n]+/s", "\n", $s);
		return $s;
	}

	public function html_to_safe_str($s, $length) {
		$s = str_replace(array("\n", "\r", "\t", "\v", "\0", "\x0B"), '', preg_replace("/[^\x20-\xFF]/", " ", trim(@strval($s))));
			$s = $this->clean_xhtml($s);
		$s = str_replace(array("&#8211;","&#8212;","&#171;","&#187;"), array("-","—","«","»"), $s);
		$s = $this->remove_ents($s);
		$s = $this->remove_tags($s);
		$s = $this->ensure_lt_gt($s);
		$s = $this->ord_space($s);
		if (!empty($length) && (mb_strlen($s, mb_detect_encoding($s)) > $length)) {
			$s = mb_substr($s, 0, ($length - 5), mb_detect_encoding($s)) . ' [...]';
		}
		$s = $this->ensure_amp($s);
		return $s;
	}

	public function random_anchor() {
		$r = range(0, 9);
		shuffle($r);
		$ds = '';
		foreach ($r as $d) {
			$ds .= $d;
		}
		return $ds;
	}
}
